Imports System.Data.SqlClient
Imports System.Configuration
''' -----------------------------------------------------------------------------
''' Project	 : CObject
''' Class	 : CTransaction
''' 
''' -----------------------------------------------------------------------------
''' <summary>
''' Takes a queue of business objects and handles update, insert or delete commands within a
''' single transaction 
''' </summary>
''' -----------------------------------------------------------------------------
Public Class CTransaction
    Public Event BeforeSave(ByVal poCObject As CObject, ByVal poTransaction As SqlTransaction, ByVal loConnection As SqlConnection)
    Public Event AfterSave(ByVal poCobject As CObject, ByVal poTransaction As SqlTransaction, ByVal loConnection As SqlConnection)
	Public Event TransactionOutput(ByVal poOutPut As Object)
	Private mqueObjectsToSave As Queue
    Private moConn As IDbConnection
    Private moTran As IDbTransaction
	Private mbIsChildTransaction As Boolean = False
    Private mbHasOutPut As Boolean
    Private mbTestMode As Boolean = False
    Private Sub Init()
        mqueObjectsToSave = New Queue
    End Sub
    '''<remarks>
    '''Use this constructor when you already have a transaction. 
    '''</remarks>
    Public Sub New(ByVal poTransaction As IDbTransaction, ByVal poConnection As IDbConnection)
        Init()
        moConn = poConnection
        moTran = poTransaction
        mbIsChildTransaction = True
    End Sub
    Public Sub New()
        Init()
	End Sub

	'''<remarks>
	'''If stored proc has output paramater set this to true.
	'''Output will be raised in TransactionOutput event
	'''</remarks>
	Public Property HasOutPut() As Boolean
		Get
			Return mbHasOutPut
		End Get
		Set(ByVal Value As Boolean)
			mbHasOutPut = Value
		End Set
    End Property
    Public ReadOnly Property TransactionList() As Queue
        Get
            Return mqueObjectsToSave
        End Get
    End Property

    Public Sub AddObject(ByVal poDataObject As CObject)
        mqueObjectsToSave.Enqueue(poDataObject)
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' The save function will use the connection of the first Cobject in the Queue
    ''' You should save only like Cobjects in one transaction.
    ''' If it becomes necessary to save multiple types of Cobjects this will have to be modified to
    ''' 
    ''' </summary>
    ''' <remarks>
    ''' </remarks>   
    ''' -----------------------------------------------------------------------------
    Public Sub Save()
        Dim loCObject As CObject
        Dim lsqlCommand As SqlCommand

        Dim loState As DataState

        Dim loConnServer As ConnectionServer.Connection = New ConnectionServer.Connection
        If mqueObjectsToSave.Count = 0 Then Exit Sub
        loCObject = mqueObjectsToSave.Peek
        If moConn Is Nothing Then
            moConn = loConnServer.GetConnection(loCObject.SourceDataBase)
        End If
        If moTran Is Nothing Then
            moTran = moConn.BeginTransaction
        End If
        'Try
        Do Until mqueObjectsToSave.Count = 0
            loCObject = mqueObjectsToSave.Dequeue
            loState = loCObject.State
            RaiseEvent BeforeSave(loCObject, moTran, moConn)
            lsqlCommand = loCObject.GetCommandObj
            lsqlCommand.Connection = moConn
            lsqlCommand.Transaction = moTran
            If lsqlCommand.CommandText.Length > 0 Then
                If HasOutPut Then
                    Dim loOutPut As Object
                    loOutPut = lsqlCommand.ExecuteScalar
                    RaiseEvent TransactionOutput(loOutPut)
                Else
                    lsqlCommand.ExecuteNonQuery()

                    If loState = DataState.IsNew Then
                        lsqlCommand.CommandText = "SELECT @@IDENTITY"
                        loCObject.SetProperty(loCObject.Key, lsqlCommand.ExecuteScalar)
                    End If
                End If
            End If
            RaiseEvent AfterSave(loCObject, moTran, moConn)
        Loop
        If Not mbIsChildTransaction Then

            If Not System.Environment.GetEnvironmentVariable("TestMode") Is Nothing _
            AndAlso CBool(System.Environment.GetEnvironmentVariable("TestMode")) Then
                moTran.Rollback()
            Else
                moTran.Commit()
            End If
            If moConn.State <> ConnectionState.Closed Then
                moConn.Close()
            End If
        End If
 
    End Sub
 
End Class
